#include "os_linux.h"
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/stat.h>
#include <stdlib.h>


//typedef pthread_mutex_t* CMS_OS_MUTEX;
CMS_OS_MUTEX cms_os_mutex_create()
{
	CMS_OS_MUTEX cms_mutex;
	pthread_mutexattr_t* attr = new pthread_mutexattr_t();
	pthread_mutexattr_init(attr);

	//这个属性必须加上，避免同一个线程多次加同一个锁时失败，应该允许这种情况
	pthread_mutexattr_settype(attr, PTHREAD_MUTEX_RECURSIVE);
	pthread_mutex_t* mutex = new pthread_mutex_t();
	pthread_mutex_init(mutex, attr);
	cms_mutex.pMutex = mutex;
	cms_mutex.pMutexAttr = attr;
	return cms_mutex;
}

void cms_os_mutex_delete(CMS_OS_MUTEX m)
{
	pthread_mutex_destroy(m.pMutex);
	pthread_mutexattr_destroy(m.pMutexAttr);
	delete m.pMutex;
	delete m.pMutexAttr;
}

void cms_os_mutex_lock(CMS_OS_MUTEX m)
{
    pthread_mutex_lock(m.pMutex);
}

void cms_os_mutex_unlock(CMS_OS_MUTEX m)
{
	pthread_mutex_unlock(m.pMutex);
}

cms_os_mutex_wrapper::cms_os_mutex_wrapper(CMS_OS_MUTEX mutex)
{
	m_mutex = mutex;
	cms_os_mutex_lock(mutex);
}

cms_os_mutex_wrapper::~cms_os_mutex_wrapper()
{
	cms_os_mutex_unlock(m_mutex);
}

//typedef sem_t* CMS_OS_SEM;
CMS_OS_SEM cms_os_sem_create(long maxCount)
{
	CMS_OS_SEM pSem = new sem_t();
	sem_init(pSem, 0, 0);
	return pSem;
}

void cms_os_sem_delete(CMS_OS_SEM s)
{
	sem_destroy(s);
	delete s;
}

void cms_os_sem_wait(CMS_OS_SEM s)
{
	sem_wait(s);
}

void cms_os_sem_activate(CMS_OS_SEM s)
{
	sem_post(s);
}

//typedef pthread_t CMS_OS_THREAD;
//typedef pthread_t CMS_OS_TID;
//typedef UINT (_stdcall* ThreadProc) (void*);
CMS_OS_THREAD cms_os_thread_create(CMS_OS_TID* pTid, ThreadProc proc, void* pArg)
{
	pthread_create(pTid, NULL, proc, pArg);
	return *pTid;
}

void cms_os_thread_delete(CMS_OS_THREAD thread)
{
	pthread_cancel(thread);
}

//typedef sem_t* CMS_OS_EVENT;
CMS_OS_EVENT cms_os_event_create()
{
	CMS_OS_EVENT pEvent = new sem_t();
	sem_init(pEvent, 0, 0);
	return pEvent;
}

void cms_os_event_delete(CMS_OS_EVENT event)
{
	sem_destroy(event);
	delete event;
}

void cms_os_event_wait(CMS_OS_EVENT event)
{
	sem_wait(event);
}

void cms_os_event_signal(CMS_OS_EVENT event)
{
	sem_post(event);
}

void cms_sleep(int miniseconds)
{
	usleep(miniseconds * 1000);
}

bool cms_uuid_equal(CMS_UUID u1, CMS_UUID u2)
{
	return (u1 == u2);
}

bool cms_uuid_high_equal(CMS_UUID u1, CMS_UUID u2)
{
	u1 = u1 & 0xFFFFFFFF00000000;
	u2 = u2 & 0xFFFFFFFF00000000;
	return (u1 == u2);
}

void getcurrentdir(std::string& sPath)
{
	char buf[4097] = {0};
	long size = pathconf(".", _PC_PATH_MAX);
	char *ptr = new char[size];
	memset(ptr, 0 , size);
	sprintf(ptr, "/proc/%d/exe", getpid());

	readlink(ptr, buf, size);
	delete [] ptr;
	ptr = NULL;
	sPath = buf;
	int nPos = sPath.find_last_of("/");
	sPath = sPath.substr(0, nPos);
}

int deleteDir(const char* sPathName)
{
	char cmd[260];
	memset(cmd, 0, sizeof(cmd));
	sprintf(cmd, "rm -rf %s ", sPathName);
	system(cmd);
	return 0;
}

CMS_UUID cms_generate_uuid()
{
	CMS_UUID uuid = 0;
	char* puuid = (char*)&uuid;
	int tid = pthread_self();
	time_t t = time(0);
	srand(t);
	int pid = rand()+rand()*(int)t;

	static int count = 0;
	static CMS_OS_MUTEX mutex;
	if (uuid == 0)
	{
		mutex = cms_os_mutex_create();
	}
	{
		cms_os_mutex_wrapper guard(mutex);
		count++;
		tid += count;
		pid += tid * count;
	}
	memcpy(puuid, &tid, 4);
	memcpy(puuid+4, &pid, 4);
	return uuid;
}

int createDir(const char* sPathName)
{
	char DirName[256];
	strcpy(DirName, sPathName);
	int len = strlen(DirName);
	if(DirName[len - 1] != '/')
		strcat(DirName, "/");
	len = strlen(DirName);
	for(int i = 1; i < len; i++)
	{
		if(DirName[i] == '/')
		{
			DirName[i] = 0;
			if(access(DirName, NULL) != 0)
			{
				if(mkdir(DirName,0755) == -1) return -1;
			}
			DirName[i] = '/';
		}
	}
	return 0;
}

bool fileExists(const char* sfileName)
{
	if ((access(sfileName, F_OK)) != -1)	return true;

	return false;
}

void getcurrenttime(char* pTime)
{
 	time_t t = time(0);
	strftime(pTime, 1024, "%Y-%m-%d %H:%M:%S", localtime(&t));
}

std::string getcurrenttime()
{
	time_t t = time(0);
	char pTime[128];
	memset(pTime, 0, 128);
	strftime(pTime, 1024, "%Y%m%d%H%M%S", localtime(&t));
	return (std::string)pTime;
}

void startProcess(const char* cmd)
{
	system(cmd);
}

void terminateProcess(const char* processName)
{
	char pCmd[MAX_PATH];
	memset(pCmd, 0, MAX_PATH);
	sprintf(pCmd, "pkill -9 %s", processName);
	system(pCmd);
}

void cleanFiles(const char* folderName)
{
	char pCmd[MAX_PATH];
	memset(pCmd, 0, MAX_PATH);
	sprintf(pCmd, "rm -rf %s*", folderName);
	system(pCmd);
}

int cal_cpu(CPU_OCCUPY* o, CPU_OCCUPY* n)
{
	int cpu_use = 0;
	unsigned long od = (unsigned long)(o->user + o->nice + o->system + o->idle);
	unsigned long nd = (unsigned long)(n->user + n->nice + n->system + n->idle);
	unsigned long id = (unsigned long)(n->user - o->user);
	unsigned long sd = (unsigned long)(n->system - o->system);

	if((nd-od) != 0) cpu_use=(int)((sd+id)*100)/(nd-od);
	else cpu_use=0;

	if(cpu_use > 100 || cpu_use < 0) cpu_use = 0;
	return cpu_use;
}

void get_cpuoccupy(CPU_OCCUPY* cpust)
{
	char buff[256];
	CPU_OCCUPY* cpu_occupy;
	cpu_occupy = cpust;
	FILE* fd = fopen("/proc/stat", "r");
	fgets(buff, sizeof(buff), fd);
	sscanf(buff, "%s %u %u %u %u", cpu_occupy->name, &cpu_occupy->user, &cpu_occupy->nice,&cpu_occupy->system,&cpu_occupy->idle);
	fclose(fd);
}

void get_freemem(long& totalram, long& freeram, int& usedrate)
{
	struct sysinfo info;
	sysinfo(&info);
	
	totalram = info.totalram/1024;
	freeram = info.freeram/1024;
	usedrate = (int)((totalram-freeram)*100/totalram);
	//printf("totalram = %llu, free=%llu\n", totalram, freeram);
}

std::string getCurrentProcessName(const char* exedir)
{
	char processidr[PATH_MAX];
	strcpy(processidr, exedir);
	char processname[1024];

	char* path_end;
	int len;
	if (readlink("/proc/self/exe", processidr, len)<=0) return "111";

	std::string a = processidr;
	int pos = a.find_last_of("/") + 1;
	a = a.substr(pos, a.size()  - pos);
	return a ;
}

std::string cms_os_getcurr_path()
{
    std::string sPath;
    char buf[4097] = {0};
    long size = pathconf(".", _PC_PATH_MAX);
    char *ptr = new char[size];
    memset(ptr, 0 , size);
    sprintf(ptr, "/proc/%d/exe", getpid());

    readlink(ptr, buf, size);
    delete [] ptr;
    ptr = NULL;
    sPath = buf;
    int nPos = sPath.find_last_of("/");
    sPath = sPath.substr(0, nPos);
    return sPath;
}

CMS_OS_THREAD cms_os_thread_current()
{
    return pthread_self();
}

std::string cms_os_generateId(std::string serviceName)
{
    static CMS_OS_MUTEX mutex = cms_os_mutex_create();
    static int count = 0;
    char buf[1024];

    int tid = cms_os_thread_current();
    int pid = getpid();

    {
        cms_os_mutex_wrapper guard(mutex);
        count ++;
        tid += count;
        pid += tid * count;
    }

    sprintf(buf, "%s_%x_%x", serviceName.c_str(), tid, pid);
    return buf;
}

HMODULE LoadLibrary(char* libPath)
{
    return dlopen(libPath, RTLD_NOW);
}

FARPROC GetProcAddress(HMODULE handle, LPCTSTR procName)
{
    return dlsym(handle, procName);
}

BOOL FreeLibrary(HMODULE handle)
{
    if(0 == dlclose(handle)) return 1;
    return 0;
}
